#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/sysctl.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/ratelimit.h>

#include <asm/current.h>
//确定主设备号，也可以让内核自动分配

static int major = 0; //主设备号
static char kernel_buf [1024];//缓存
static struct  class *hello_class;// 设备节点
#define MIN(a,b)  (a<b ? a:b)


//实现对应的drv_open  drv_read drw_wirter 等函数

static ssize_t  read_hello_driver (struct file * file, char __user * buf, size_t size, loff_t *offset) //app read 的时候会调用到这个函数
{
    int err;
    printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__); //打印调试信息 ，文件名， 函数，行号
    err = copy_to_user(buf, kernel_buf,MIN(1024,size));// 讲数据拷贝到app 上去
    return MIN(1024,size);
}
static ssize_t  write_hello_driver (struct file * file, const char __user * buf, size_t size, loff_t * offset)    //APP  write 的时候会调用到这个函数
{
    int err;
    printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号
    err = copy_from_user(kernel_buf,buf,MIN(1024,size)); // 把数据 从app中拷贝到内核中
    return MIN(1024,size);
}
static int open_hello_driver (struct inode * node, struct file * file)  //app  open 调用这个函数
 {
     printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号
     return  0;
}
static int release_hello_driver (struct inode * node, struct file * file)  
{
    printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号
     return  0;
}


//定义file_operations结构体
static struct file_operations hello_drv = 
{
    .owner		= THIS_MODULE, //linux 中的一种特殊的初始化方式   指定初始化
   	.open		= open_hello_driver,
	.read		= read_hello_driver,
	.release	= release_hello_driver,
	.write		= write_hello_driver,

};
//把file_operations 结构体告诉内核 register_chrdev


// 谁来注册驱动程序？ 通过入口函数  在执行insmod 命令的时候会去调用 这个入口函数
static int __init hello_drv_init(void)
{
    int err;
    printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号

    /*
    static inline int register_chrdev(unsigned int major, const char *name,
				  const struct file_operations *fops)
    */
    major = register_chrdev(0,"hello",&hello_drv);  //调用此函数内核 会创建一个 /dev/hello  设备出来
    hello_class = class_create(THIS_MODULE,"hello_class");  //创建设备节点
    err = PTR_ERR(&hello_class); //类型转换
    if(IS_ERR(hello_class)) //判断设备节点是否创建成功
        {
            printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号
            /*
            static inline void unregister_chrdev(unsigned int major, const char *name)
                    {
                    __unregister_chrdev(major, 0, 256, name);
                    }
           */
            unregister_chrdev(major,"hello");
            return -1;
        }    
        device_create(hello_class,NULL,MKDEV(major,0),NULL,"hello"); //创建设备   /dev/hello
        return  0;
}
//卸载驱动程序时，出口函数会调用 unreagister_chardev函数 来卸载当前驱动程序
/*
static void __exit
srm_env_exit(void)
{
	remove_proc_subtree(BASE_DIR, NULL);
	printk(KERN_INFO "%s: unloaded successfully\n", NAME);
}
*/
static void __exit hello_drv_exit(void)
{
     printk("%s %s line %d \n",__FILE__,__FUNCTION__,__LINE__);//打印调试信息 ，文件名， 函数，行号
     device_destroy(hello_class,MKDEV(major,0));  //删除设备
     class_destroy(hello_class);//删除设备节点
     unregister_chrdev(major,"hello");//注销设备
}


//提供设备信息，自动创建设备节点, class_create  device_create
module_init(hello_drv_init);  //申明入口
module_exit(hello_drv_exit);//申明出口

MODULE_LICENSE("GPL");








